//普通指针new和new[]后需要 delete和delete[]释放，容易搞错
//智能指针就可以避免这一问题,但智能指针只能管理new分配的内存（即堆区）
//智能指针是类模板， 在栈上创建指针对象，普通指针交给智能指针对象
//智能指针对象过期时，调用析构函数释放普通指针内存

//有三种智能指针  unique_ptr   shared_ptr   weak_ptr





//unique_ptr独享它所指向的对象，当unique_ptr被销毁时，指向的对象也随机被销毁
#include<memory>	//智能指针头文件
#include<iostream>
#include<vector>
using namespace std;

class AA
{
public:
	AA()
	{
		cout << m_name << "调用构造函数AA()。" << endl;
	}

	AA(const string& name) :m_name(name)
	{
		cout << "调用构造函数AA(" << m_name << ") " << endl;	// "<<变量名<<"
	}

	~AA()
	{
		cout << "调用了析构函数~AA()" << endl;
	}
	string m_name;
	
};

int main()
{
	
	AA* p = new AA("张三");		//在堆区创建一个普通指针，指向new出来的对象地址  
					// 调用构造函数AA(张三)
	unique_ptr<AA> pu1(p);	//智能指针类型为AA， 智能指针名pul， p是被管理的指针
				// 调用析构函数AA(张三)	 没有使用delete也销毁了对象

	//智能指针使用和普通指针使用一样
	cout << "m_name = " << (*pu1).m_name << endl;	//m_name = 张三
	cout << "m_name = " << pu1->m_name << endl;		//m_name = 张三
	cout << "m_name = " << (*p).m_name << endl;		//m_name = 张三
	cout << "m_name = " << p->m_name << endl;		//m_name = 张三
	//智能指针自动销毁								//调用了析构函数~AA()
	delete p;			//普通指针手动销毁			//调用了析构函数~AA()		



	//初始化
	//法一
	unique_ptr<AA> p0(new AA("李四"));		//（最常用）分配内存并初始化
	//法二
	unique_ptr<AA> p1 = make_unique<AA>("王五");
	//法三(不推荐)	
	AA* p2 = new AA("赵六");	//p2是裸指针
	unique_ptr<AA> p3(p2);	//用户已存在的地址初始化
	//不推荐方法三，若用此法多定义几个智能指针
	unique_ptr<AA> pp3(p2);
	unique_ptr<AA> ppp3(p2);	//程序运行会崩溃，因为多次释放同一内存即指针p2，相当于操作野指针


	//unique_ptr智能指针不能赋值构造和拷贝构造
	p1 = p3;	//报错,删除了赋值构造函数
	unique_ptr<AA> pp1 = p1;	//报错，删除了拷贝构造函数
	
	
	//.get()可返回裸指针
	AA* q = new AA("张三和李四");
	unique_ptr<AA> q1(q);
	cout << "裸指针的值是：" << q << endl;				//裸指针的值是：00000229C51FBF40
	cout << "q1的值是是：" << q1 << endl;				//q1的值是是：00000229C51FBF40
	cout << "q1.get()的值是：" << q1.get() << endl;		//q1.get()的值是：00000229C51FBF40
	cout << "&q1的值是：" << &q1 << endl;	//q1的地址	//&q1的值是：000000568B8FF6E8
 	//由于unique_ptr中重载了<<符号，所以cout输出unique_ptr对象时显示会原始指针




	//当unique_ptr指针作为函数参数时
	//1.传引用(不能传值，因为unique_ptr没有构造函数会报错)
	//2.传地址，很少用，不方便
	//3.传裸指针


	//unique_ptr指针不支持的运算（+， -， ++, --）

	return 0;


}















#include<memory>	
#include<iostream>
#include<vector>
#include<functional>
using namespace std;
class AA
{
public:
	AA()
	{
		cout << m_name << "调用构造函数AA()。" << endl;
	}

	AA(const string& name) :m_name(name)
	{
		cout << "调用构造函数AA(" << m_name << ") " << endl;	// "<<变量名<<"
	}

	~AA()
	{
		cout << "调用了析构函数~AA("<<m_name<<")" << endl;
	}
	string m_name;
	
};

int main()
{
	auto func = []() {	//auto为function<unique_ptr<AA>()>
		unique_ptr<AA> pp(new AA("王五"));
		return pp;
	};
	unique_ptr<AA> pu1(new AA("张三"));

	unique_ptr<AA> pu2;
	//pu2 = pu1;	//报错，没有赋值函数
	pu2 = unique_ptr<AA>(new AA("李四"));	//用匿名对象给pu2赋值

	cout << "调用func()之前" << endl;

	pu2 = func();	//用func()函数给pu2赋值，此处又可以使用赋值函数（奇迹1）
	cout << "调用func()之后" << endl;


	/*执行结果如下:
	调用构造函数AA(张三)
	调用构造函数AA(李四)
	调用func()之前
	调用构造函数AA(王五)		//再接手func()中的 王五（奇迹2）
	调用了析构函数~AA(李四)		//pu2首先释放pu2中存的 李四
	调用func()之后
	调用了析构函数~AA(王五)		
	调用了析构函数~AA(张三)
	*/
    //若将unique_ptr<AA> pp(new AA("王五"));放在外面pp成为全局对象，又会报错（奇迹3）

	return 0;
}








//用nullptr给unique_ptr赋值将会释放对象
unique_ptr<AA> func()
{
    unique_ptr<AA> pp(new AA("王五"));
    return pp;
}
int main()
{
    unique_ptr<AA> pu(new AA("张三"));
    cout << "赋值前" << endl;
    if(pu!=nullptr)
        cout << "pu不是空的" << endl;
    pu = nullptr;
    cout << "赋值后" << endl;
    if(pu==nullptr)
        cout << "pu是空的" << endl;
    
    return 0;
}
/*
调用构造函数AA(张三)
赋值前
pu不是空的
调用了析构函数~AA(张三)
赋值后
pu是空的
*/








//release()释放对原始指针的控制权，将unique_ptr置为空，返回裸指针。
//（可用于把unique_ptr传递给子函数，子函数负责释放对象）
//std::move()可以转移对原始指针的控制权
//（可用于把unique_ptr传递给子函数，子函数形参也是unique_ptr）


//函数func1需要一个指针，只是用一下，但不对这个指针负责
void func1(const AA* a) //老式传参
{
    cout << a->m_name << endl;
}
//函数func2需要一个指针，并且对他负责
void func2(AA* a)
{
    cout << a->m_name << endl;
    delete a;
}
//函数func3需要一个unique_ptr,只是用一下，但不对这个指针负责
void func3（const unique_ptr<AA> &a) //传引用
{
    coutt << a->m_name << endl;
}
//函数func4需要一个unique_ptr，并且对他负责
void func4（const unique_ptr<AA> a) 
{
    coutt << a->m_name << endl;
}

int main()
{
    unique_ptr<AA> pu(new AA("张三"));
    cout << "开始调用函数。" << endl;
    func1(pu.get());
    func2(pu.release());
    func3(pu);
    func4(move(pu));
    cout << "调用函数完成。" << endl;

    return 0;
}










#include<memory>	//智能指针头文件
#include<iostream>
#include<vector>
#include<functional>
using namespace std;

class AA
{
public:
	AA()
	{
		cout << m_name << "调用构造函数AA()。" << endl;
	}

	AA(const string& name) :m_name(name)
	{
		cout << "调用构造函数AA(" << m_name << ") " << endl;	// "<<变量名<<"
	}

	~AA()
	{
		cout << "调用了析构函数~AA(" << m_name << ")" << endl;
	}
	string m_name;

};

//release()释放对原始指针的控制权，将unique_ptr置为空，返回裸指针。
//（可用于把unique_ptr传递给子函数，子函数负责释放对象）
//std::move()可以转移对原始指针的控制权
//（可用于把unique_ptr传递给子函数，子函数形参也是unique_ptr）


//函数func1需要一个指针，只是用一下，但不对这个指针负责
void func1(const AA* a) //老式传参
{
	cout << a->m_name << endl;
}
//函数func2需要一个指针，并且对他负责
void func2(AA* a)	//老式传参
{
	cout << a->m_name << endl;
	delete a;
}
//函数func3需要一个unique_ptr,只是用一下，但不对这个指针负责
void func3(const unique_ptr<AA> &a) //传引用
{
	cout << a->m_name << endl;
}
//函数func4需要一个unique_ptr，并且对他负责
void func4( unique_ptr<AA> a)	//值传递
{
	cout << a->m_name << endl;
}

int main()
{
	unique_ptr<AA> pu(new AA("张三"));
	cout << "开始调用函数。" << endl;
	//func1(pu.get());
	//func2(pu.release());	//pu自己成为空指针
	//func3(pu);
	func4(move(pu));	//pu自己成为空指针
	cout << "调用函数完成。" << endl;

	return 0;
}



//rest()释放对象
//pp.rest(nullptr)	//释放pp对象指向的资源对象，参数nullptr可以不要
//pp.rest(new AA("bbb))	//释放pp所指资源对象，同时pp指向心得对象


//swap()交换两个unique_ptr的控制权



//unique_ptr也可以像普通指针那样多态
//父类指针指向子类对象



//unique_ptr并不是绝对安全，如果程序中调用exit()退出，全局的unique_ptr会自动释放
//但局部的unique_ptr无法释放





//智能指针数组
int main()
{
	//普通指针数组
	AA* parr1 = new AA[2];	//普通指针数组定义
	AA* parr2 = new AA[2]{ string("张三"), string("李四") };	//定义+初始化	
	parr1[0].m_name = "王五";
	parr1[1].m_name = "赵六";
	cout << parr1[0].m_name << endl;
	cout << parr2[1].m_name << endl;
	delete []parr1;
	delete []parr2;
	cout << "-------------------------------" << endl<<endl;

	//unique_ptr数组
	unique_ptr<AA[]> parr3(new AA[2]);
	parr3[0].m_name = "Tom";
	parr3[1].m_name = "Jerry";
	cout << parr3[0].m_name << " and " << parr3[1].m_name << endl;

	return 0;
}








